Trò chơi Tic-Tac-Toe, game đánh caro full source code
- ChatGui.cs
- DemoChat /
- Demos /
- Photon Unity Networking /
- Assets /
- project /
2 using System.Collections.Generic;
3 using ExitGames.Client.Photon.Chat;
4 using UnityEngine;
5
6
7 /// <summary>
8 /// This simple Chat Server Gui uses a global chat (in lobby) and a room chat (in room).
9 /// </summary>
10 /// <remarks>
11 /// The Chat Server API in ChatClient basically lets you create any number of channels.
12 /// You just have to name them. Example: "gc" for Global Channel or for rooms: "rc"+RoomName.GetHashCode()
13 ///
14 /// This simple demo sends in a global chat when in lobby and in room channel when in room.
15 /// Create a more elaborate UI to let players chat in either channel while in room or send private messages.
16 ///
17 /// Names of users are set in Authenticate. That should be unique so users can actually get their messages.
18 ///
19 ///
20 /// Workflow:
21 /// Create ChatClient, Connect to a server with your AppID, Authenticate the user (apply a unique name)
22 /// and subscribe to some channels.
23 /// Subscribe a channel before you publish to that channel!
24 ///
25 ///
26 /// Note:
27 /// Don't forget to call ChatClient.Service(). Might later on be integrated into PUN but for now don't forget.
28 /// </remarks>
29 public class ChatGui : MonoBehaviour, IChatClientListener
30 {
31 public string ChatAppId; // set in inspector. Your Chat AppId (don't mix it with Realtime/Turnbased Apps).
32 public string[] ChannelsToJoinOnConnect; // set in inspector. Demo channels to join automatically.
33 public int HistoryLengthToFetch; // set in inspector. Up to a certain degree, previously sent messages can be fetched for context.
34 public bool DemoPublishOnSubscribe; // set in inspector. For demo purposes, we publish a default text to any subscribed channel.
35
36 public string UserName { get; set; }
37
38 private ChatChannel selectedChannel;
39 private string selectedChannelName; // mainly used for GUI/input
40 private int selectedChannelIndex = 0; // mainly used for GUI/input
41 bool doingPrivateChat;
42
43
44 public ChatClient chatClient;
45
46 // GUI stuff:
47 public Rect GuiRect = new Rect(0, 0, 250, 300);
48 public bool IsVisible = true;
49 public bool AlignBottom = false;
50 public bool FullScreen = false;
51
52 private string inputLine = "";
53 private string userIdInput = "";
54 private Vector2 scrollPos = Vector2.zero;
55 private static string WelcomeText = "Welcome to chat.\\help lists commands.";
56 private static string HelpText = "\n\\subscribe <list of channelnames> subscribes channels.\n\\unsubscribe <list of channelnames> leaves channels.\n\\msg <username> <message> send private message to user.\n\\clear clears the current chat tab. private chats get closed.\n\\help gets this help message.";
57
58 public void Start()
59 {
60 DontDestroyOnLoad(this.gameObject);
61 Application.runInBackground = true; // this must run in background or it will drop connection if not focussed.
62
63 if (string.IsNullOrEmpty(this.UserName))
64 {
65 this.UserName = "user" + Environment.TickCount%99; //made-up username
66 }
67
68 chatClient = new ChatClient(this);
69 chatClient.Connect(ChatAppId, "1.0", this.UserName, null);
70
71 if (this.AlignBottom)
72 {
73 this.GuiRect.y = Screen.height - this.GuiRect.height;
74 }
75 if (this.FullScreen)
76 {
77 this.GuiRect.x = 0;
78 this.GuiRect.y = 0;
79 this.GuiRect.width = Screen.width;
80 this.GuiRect.height = Screen.height;
81 }
82
83 Debug.Log(this.UserName);
84 }
85
86 /// <summary>To avoid that the Editor becomes unresponsive, disconnect all Photon connections in OnApplicationQuit.</summary>
87 public void OnApplicationQuit()
88 {
89 if (this.chatClient != null)
90 {
91 this.chatClient.Disconnect();
92 }
93 }
94
95 public void Update()
96 {
97 if (this.chatClient != null)
98 {
99 this.chatClient.Service(); // make sure to call this regularly! it limits effort internally, so calling often is ok!
100 }
101 }
102
103 public void OnGUI()
104 {
105 if (!this.IsVisible)
106 {
107 return;
108 }
109
110 GUI.skin.label.wordWrap = true;
111 //GUI.skin.button.richText = true; // this allows toolbar buttons to have bold/colored text. nice to indicate new msgs
112 //GUILayout.Button("<b>lala</b>"); // as richText, html tags could be in text
113
114
115 if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.KeypadEnter || Event.current.keyCode == KeyCode.Return))
116 {
117 if ("ChatInput".Equals(GUI.GetNameOfFocusedControl()))
118 {
119 // focus on input -> submit it
120 GuiSendsMsg();
121 return; // showing the now modified list would result in an error. to avoid this, we just skip this single frame
122 }
123 else
124 {
125 // assign focus to input
126 GUI.FocusControl("ChatInput");
127 }
128 }
129
130 GUI.SetNextControlName("");
131 GUILayout.BeginArea(this.GuiRect);
132
133 GUILayout.FlexibleSpace();
134
135 if (this.chatClient.State != ChatState.ConnectedToFrontEnd)
136 {
137 GUILayout.Label("Not in chat yet.");
138 }
139 else
140 {
141 List<string> channels = new List<string>(this.chatClient.PublicChannels.Keys); // this could be cached
142 int countOfPublicChannels = channels.Count;
143 channels.AddRange(this.chatClient.PrivateChannels.Keys);
144
145 if (channels.Count > 0)
146 {
147 int previouslySelectedChannelIndex = this.selectedChannelIndex;
148 int channelIndex = channels.IndexOf(this.selectedChannelName);
149 this.selectedChannelIndex = (channelIndex >= 0) ? channelIndex : 0;
150
151 this.selectedChannelIndex = GUILayout.Toolbar(this.selectedChannelIndex, channels.ToArray(), GUILayout.ExpandWidth(false));
152 this.scrollPos = GUILayout.BeginScrollView(this.scrollPos);
153
154 this.doingPrivateChat = (this.selectedChannelIndex >= countOfPublicChannels);
155 this.selectedChannelName = channels[this.selectedChannelIndex];
156
157 if (this.selectedChannelIndex != previouslySelectedChannelIndex)
158 {
159 // changed channel -> scroll down, if private: pre-fill "to" field with target user's name
160 this.scrollPos.y = float.MaxValue;
161 if (this.doingPrivateChat)
162 {
163 string[] pieces = this.selectedChannelName.Split(new char[] {':'}, 3);
164 this.userIdInput = pieces[1];
165 }
166 }
167
168 GUILayout.Label(ChatGui.WelcomeText);
169
170 if (this.chatClient.TryGetChannel(selectedChannelName, this.doingPrivateChat, out this.selectedChannel))
171 {
172 for (int i = 0; i < this.selectedChannel.Messages.Count; i++)
173 {
174 string sender = this.selectedChannel.Senders[i];
175 object message = this.selectedChannel.Messages[i];
176 GUILayout.Label(string.Format("{0}: {1}", sender, message));
177 }
178 }
179
180 GUILayout.EndScrollView();
181 }
182 }
183
184
185 GUILayout.BeginHorizontal();
186 if (doingPrivateChat)
187 {
188 GUILayout.Label("to:", GUILayout.ExpandWidth(false));
189 GUI.SetNextControlName("WhisperTo");
190 this.userIdInput = GUILayout.TextField(this.userIdInput, GUILayout.MinWidth(100), GUILayout.ExpandWidth(false));
191 string focussed = GUI.GetNameOfFocusedControl();
192 if (focussed.Equals("WhisperTo"))
193 {
194 if (this.userIdInput.Equals("username"))
195 {
196 this.userIdInput = "";
197 }
198 }
199 else if (string.IsNullOrEmpty(this.userIdInput))
200 {
201 this.userIdInput = "username";
202 }
203
204 }
205 GUI.SetNextControlName("ChatInput");
206 inputLine = GUILayout.TextField(inputLine);
207 if (GUILayout.Button("Send", GUILayout.ExpandWidth(false)))
208 {
209 GuiSendsMsg();
210 }
211 GUILayout.EndHorizontal();
212 GUILayout.EndArea();
213 }
214
215 private void GuiSendsMsg()
216 {
217 if (string.IsNullOrEmpty(this.inputLine))
218 {
219
220 GUI.FocusControl("");
221 return;
222 }
223
224 if (this.inputLine[0].Equals('\\'))
225 {
226 string[] tokens = this.inputLine.Split(new char[] {' '}, 2);
227 if (tokens[0].Equals("\\help"))
228 {
229 this.PostHelpToCurrentChannel();
230 }
231 if (tokens[0].Equals("\\state"))
232 {
233 int newState = int.Parse(tokens[1]);
234 this.chatClient.SetOnlineStatus(newState, new string[] { "i am state " + newState }); // this is how you set your own state and (any) message
235 }
236 else if (tokens[0].Equals("\\subscribe") && !string.IsNullOrEmpty(tokens[1]))
237 {
238 this.chatClient.Subscribe(tokens[1].Split(new char[] {' ', ','}));
239 }
240 else if (tokens[0].Equals("\\unsubscribe") && !string.IsNullOrEmpty(tokens[1]))
241 {
242 this.chatClient.Unsubscribe(tokens[1].Split(new char[] {' ', ','}));
243 }
244 else if (tokens[0].Equals("\\clear"))
245 {
246 if (this.doingPrivateChat)
247 {
248 this.chatClient.PrivateChannels.Remove(this.selectedChannelName);
249 }
250 else
251 {
252 ChatChannel channel;
253 if (this.chatClient.TryGetChannel(this.selectedChannelName, this.doingPrivateChat, out channel))
254 {
255 channel.ClearMessages();
256 }
257 }
258 }
259 else if (tokens[0].Equals("\\msg") && !string.IsNullOrEmpty(tokens[1]))
260 {
261 string[] subtokens = tokens[1].Split(new char[] {' ', ','}, 2);
262 string targetUser = subtokens[0];
263 string message = subtokens[1];
264 this.chatClient.SendPrivateMessage(targetUser, message);
265 }
266 }
267 else
268 {
269 if (this.doingPrivateChat)
270 {
271 this.chatClient.SendPrivateMessage(this.userIdInput, this.inputLine);
272 }
273 else
274 {
275 this.chatClient.PublishMessage(this.selectedChannelName, this.inputLine);
276 }
277 }
278
279 this.inputLine = "";
280 GUI.FocusControl("");
281 }
282
283 private void PostHelpToCurrentChannel()
284 {
285 ChatChannel channelForHelp = this.selectedChannel;
286 if (channelForHelp != null)
287 {
288 channelForHelp.Add("info", ChatGui.HelpText);
289 }
290 else
291 {
292 Debug.LogError("no channel for help");
293 }
294 }
295
296 public void OnConnected()
297 {
298 if (this.ChannelsToJoinOnConnect != null && this.ChannelsToJoinOnConnect.Length > 0)
299 {
300 this.chatClient.Subscribe(this.ChannelsToJoinOnConnect, this.HistoryLengthToFetch);
301 }
302
303 this.chatClient.AddFriends(new string[] {"tobi", "ilya"}); // Add some users to the server-list to get their status updates
304 this.chatClient.SetOnlineStatus(ChatUserStatus.Online); // You can set your online state (without a mesage).
305 }
306
307 public void OnDisconnected()
308 {
309 }
310
311 public void OnChatStateChange(ChatState state)
312 {
313 // use OnConnected() and OnDisconnected()
314 // this method might become more useful in the future, when more complex states are being used.
315 }
316
317 public void OnSubscribed(string[] channels, bool[] results)
318 {
319
320 // this demo can automatically send a "hi" to subscribed channels. in a game you usually only send user's input!!
321 if (this.DemoPublishOnSubscribe)
322 {
323 foreach (string channel in channels)
324 {
325 this.chatClient.PublishMessage(channel, "says 'hi' in OnSubscribed(). "); // you don't HAVE to send a msg on join but you could.
326 }
327 }
328 }
329
330 public void OnUnsubscribed(string[] channels)
331 {
332 }
333
334 public void OnGetMessages(string channelName, string[] senders, object[] messages)
335 {
336 if (channelName.Equals(this.selectedChannelName))
337 {
338 this.scrollPos.y = float.MaxValue;
339 }
340 }
341
342 public void OnPrivateMessage(string sender, object message, string channelName)
343 {
344 // as the ChatClient is buffering the messages for you, this GUI doesn't need to do anything here
345 // you also get messages that you sent yourself. in that case, the channelName is determinded by the target of your msg
346 }
347
348 public void OnStatusUpdate(string user, int status, bool gotMessage, object message)
349 {
350 // this is how you get status updates of friends.
351 // this demo simply adds status updates to the currently shown chat.
352 // you could buffer them or use them any other way, too.
353
354 ChatChannel activeChannel = this.selectedChannel;
355 if (activeChannel != null)
356 {
357 activeChannel.Add("info", string.Format("{0} is {1}. Msg:{2}", user, status, message));
358 }
359
360 Debug.LogWarning("status: " + string.Format("{0} is {1}. Msg:{2}", user, status, message));
361 }
362 }
This simple Chat Server Gui uses a global chat (in lobby) and a room chat (in room).
The Chat Server API in ChatClient basically lets you create any number of channels.
You just have to name them. Example: "gc" for Global Channel or for rooms: "rc"+RoomName.GetHashCode()
This simple demo sends in a global chat when in lobby and in room channel when in room.
Create a more elaborate UI to let players chat in either channel while in room or send private messages.
Names of users are set in Authenticate. That should be unique so users can actually get their messages.
Workflow:
Create ChatClient, Connect to a server with your AppID, Authenticate the user (apply a unique name)
and subscribe to some channels.
Subscribe a channel before you publish to that channel!
Note:
Don't forget to call ChatClient.Service(). Might later on be integrated into PUN but for now don't forget.
public string ChatAppId; set in inspector. Your Chat AppId (don't mix it with RealtimeTurnbased Apps).
public string[] ChannelsToJoinOnConnect; set in inspector. Demo channels to join automatically.
public int HistoryLengthToFetch; set in inspector. Up to a certain degree, previously sent messages can be fetched for context.
public bool DemoPublishOnSubscribe; set in inspector. For demo purposes, we publish a default text to any subscribed channel.
private string selectedChannelName; mainly used for GUIinput
private int selectedChannelIndex = 0; mainly used for GUIinput
GUI stuff:
Application.runInBackground = true; this must run in background or it will drop connection if not focussed.
this.UserName = "user" + Environment.TickCount%99; made-up username
this.chatClient.Service(); make sure to call this regularly! it limits effort internally, so calling often is ok!
GUI.skin.button.richText = true; this allows toolbar buttons to have boldcolored text. nice to indicate new msgs
GUILayout.Button("lala"); as richText, html tags could be in text
focus on input -> submit it
return; showing the now modified list would result in an error. to avoid this, we just skip this single frame
assign focus to input
List
changed channel -> scroll down, if private: pre-fill "to" field with target user's name
this.chatClient.SetOnlineStatus(newState, new string[] { "i am state " + newState }); this is how you set your own state and (any) message
this.chatClient.AddFriends(new string[] {"tobi", "ilya"}); Add some users to the server-list to get their status updates
this.chatClient.SetOnlineStatus(ChatUserStatus.Online); You can set your online state (without a mesage).
use OnConnected() and OnDisconnected()
this method might become more useful in the future, when more complex states are being used.
this demo can automatically send a "hi" to subscribed channels. in a game you usually only send user's input!!
this.chatClient.PublishMessage(channel, "says 'hi' in OnSubscribed(). "); you don't HAVE to send a msg on join but you could.
as the ChatClient is buffering the messages for you, this GUI doesn't need to do anything here
you also get messages that you sent yourself. in that case, the channelName is determinded by the target of your msg
this is how you get status updates of friends.
this demo simply adds status updates to the currently shown chat.
you could buffer them or use them any other way, too.